﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Jacobi.Vst.Core;
using Jacobi.Vst.Framework;
using Aleator.Resources;

namespace Aleator.Core
{
    /// <summary>
    /// Abstraction of note class
    /// </summary>
    abstract public class Note : IComparable
    {
        #region Properties

        /// <summary>
        /// MIDI note ID
        /// </summary>
        abstract public int NoteID { get; set; }


        /// <summary>
        /// Conveneince property for Name
        /// </summary>
        public const string NamePropertyName = "Name";

        /// <summary>
        /// Name of the note
        /// </summary>
        abstract public string Name { get; }

        /// <summary>
        /// Conveneince property for ChordInterval
        /// </summary>
        public const string ChordIntervalPropertyName = "ChordInterval";

        /// <summary>
        /// This note's interval within it's chord
        /// </summary>
        abstract public string ChordInterval { get; set; }

        /// <summary>
        /// Convenience property for Interval
        /// </summary>
        public const string IntervalPropertyName = "Interval";

        /// <summary>
        /// The scale degree of the note
        /// </summary>
        abstract public int Interval { get; }

        /// <summary>
        /// Convenience property for Octave
        /// </summary>
        public const string OctavePropertyName = "Octave";

        /// <summary>
        /// This note's octave
        /// </summary>
        abstract public int Octave { get; }

        /// <summary>
        /// String representation of octave number
        /// </summary>
        [Bindable(true)]
        abstract public string OctaveStr { get; }

        /// <summary>
        /// Number of major ticks (
        /// </summary>
        abstract public int Resolution { get; }



        /// <summary>
        /// This notes quantized location in the measure
        /// </summary>
        abstract public int Location { get; set; }

        /// <summary>
        /// Integer indicating when the note should be turned off
        /// </summary>
        abstract public int OffLocation { get; set; }

        /// <summary>
        /// Measure in which the on note is sent
        /// </summary>
        abstract public int Measure { get; set; }

        /// <summary>
        /// Measure during which the off note is sent
        /// </summary>
        abstract public int OffMeasure { get; set; }

        /// <summary>
        /// How many major ticks result in one 'location' increment for the current phrase
        /// </summary>
        abstract public int MajorTickMultiplier { get; }

        /// <summary>
        /// Convenience property for Chord
        /// </summary>
        public const string ChordPropertyName = "Chord";

        /// <summary>
        /// Name of the chord this note instance is part of
        /// </summary>
        abstract public string Chord { get; }

        /// <summary>
        /// Integer reprenting the number of quantized note counts until the next note
        /// </summary>
        abstract public int Gap { get; set; }

        /// <summary>
        /// Duration this note will be played in beats
        /// </summary>
        public Duration NoteLength;

        /// <summary>
        /// The type of the note
        /// </summary>
        abstract public NoteType Type { get; set; }

        /// <summary>
        /// Convenience property for NoteInfo
        /// </summary>
        public const string NoteInfoPropertyName = "NoteInfo";

        /// <summary>
        /// Single string with some information about the note
        /// </summary>
        [Bindable(true)]
        public abstract string NoteInfo { get; set; }

        /// <summary>
        /// Fractional representation of the notes duration - 32nd, 16th, 8th, quarter, etc.
        /// </summary>
        abstract public Duration NoteDuration { get; }

        /// <summary>
        /// String representation of duration
        /// </summary>
        [Bindable(true)]
        abstract public string DurationStr { get; }

        #endregion

        #region MIDI properties

        /// <summary>
        /// NoteOn message for this note's MIDI channel
        /// </summary>majortickmul
        abstract public int MessageOnID { get; }

        /// <summary>
        /// NoteOff message for this note's MIDI channel
        /// </summary>
        abstract public int MessageOffID { get; }

        /// <summary>
        /// MIDI NoteOn event object
        /// </summary>
        public VstMidiEvent NoteOnEvent;

        /// <summary>
        /// MIDI NoteOff event object
        /// </summary>
        public VstMidiEvent NoteOffEvent;

        #endregion

        #region Enums

        #pragma warning disable 1591

        /// <summary>
        /// Enumeration of note types
        /// </summary>
        public enum NoteType
        {
            Drum,
            Bass,
            Lead,
            Rhythm,
            Arpeggio,
            Utility
        }

        /// <summary>
        /// Enumeration of note lengths
        /// </summary>
        public enum Duration
        {
            Unspecified,
            DoubleWhole,
            Whole,
            DottedHalf,
            DoubleDottedHalf,
            DottedHalfBoundDottedEigth,
            DottedHalfBoundSixteenth,
            Half,
            HalfBoundSixteenth,
            HalfBoundEigth,
            HalfBoundDottedQuater,
            HalfBoundDottedEigth,
            DottedQuarter,
            DoubleDottedQuarter,
            Quarter,
            QuarterBoundSixteenth,
            DottedEigth,
            Eigth,
            DottedSixteenth,
            Sixteenth,
            Thirtysecond,
            Sixtyfourth
        }

        #pragma warning restore 1591

        #endregion

        #region Comparison

        /// <summary>
        /// Comparison method for the sort
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        abstract public int CompareTo(object obj);

        #endregion

        #region Methods

        /// <summary>
        /// Determine this note's duration
        /// </summary>
        abstract protected void CalculateDuration();

        #endregion
    }
}
